package com.sarc.games.focus;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;

import com.sarc.games.GameAction;

public class ColorManager 
{
	private ArrayList<ColorTheme> colorThemes;
	private ChangeColorThemeAction changeColorAction;
	private int currentThemeIndex;
	
	public ColorManager()
	{
		colorThemes = new ArrayList<ColorTheme>();
		changeColorAction = null;
		currentThemeIndex = -1;
	}
	
	public void addNewColorTheme(ColorTheme theme)
	{
		colorThemes.add(theme);
	}
	
	public void setColorTheme(long time, int newThemeIndex)
	{
		if (time > 0)
		{
			changeColorAction = new ChangeColorThemeAction(
					time, 
					colorThemes.get(currentThemeIndex), 
					colorThemes.get(newThemeIndex));
		}
		
		currentThemeIndex = newThemeIndex;
	}
	
	public ColorTheme getCurrentColorTheme()
	{
		if (changeColorAction == null)
		{
			return colorThemes.get(currentThemeIndex);
		}
		else
		{
			return changeColorAction.getColorTheme();
		}
		
	}
	
	public void update(long frameTime)
	{
		if (changeColorAction != null)
		{
			changeColorAction.resolve(frameTime);
			if (changeColorAction.shouldRemove())
			{
				changeColorAction = null;
			}
		}
	}
	
	public int colorThemeCount()
	{
		return colorThemes.size();
	}
	
	public static float[] mixColor(float[] fromColor, float[] toColor, double progress)
	{
		if (fromColor.length != toColor.length) 
		{
			return null;
		}
		else
		{
			if (progress < 0) progress = 0;
			if (progress > 1) progress = 1;
			float[] newColor = new float[toColor.length];
			for (int i = 0; i < toColor.length; i++)
			{
				newColor[i] = (float) (progress * toColor[i] + (1-progress) * fromColor[i]);
			}
			return newColor;
		}
	}
	
	public class ColorTheme
	{
		ColorSet basicColorSet;
		ColorSet altColorSet;
		
		public ColorTheme(ColorSet basicColorSet)
		{
			this.basicColorSet = basicColorSet;
			this.altColorSet = null;
		}
		
		public ColorTheme(ColorSet basicColorSet, ColorSet altColorSet)
		{
			this.basicColorSet = basicColorSet;
			this.altColorSet = altColorSet;
		}
		
		public void setBasicColorSet(ColorSet newColorSet)
		{
			this.basicColorSet = newColorSet;
		}
		
		public void setAltColorSet(ColorSet newColorSet)
		{
			this.altColorSet = newColorSet;
		}
		
		public ColorSet getBasicColorSet()
		{
			return basicColorSet;
		}
		
		public boolean hasAltColorSet()
		{
			return altColorSet != null;
		}
		
		public ColorSet getAltColorSet()
		{
			return altColorSet;
		}

		public ColorSet getMixedColorSet(double progress)
		{
			
			ColorSet mixedColorSet = null;
			
			if (altColorSet != null)
			{
				mixedColorSet = new ColorSet();
				for (ColorType type : ColorType.values())
				{
					float[] color1 = basicColorSet.getColorByType(type);
					float[] color2 = altColorSet.getColorByType(type);
					float[] mixedColor = ColorManager.mixColor(color1, color2, progress);
					mixedColorSet.setColorByType(type, mixedColor);
				}
			}
			
			return mixedColorSet;
		}
	}
	
	public class ColorSet
	{
		HashMap<ColorType, float[]> colorSet;
		public ColorSet()
		{
			colorSet = new HashMap<ColorType, float[]>();
			for (ColorType type : ColorType.values())
			{
				colorSet.put(type, new float[]{1f, 1f, 1f, 1f});
			}
		}
		
		public float[] getColorByType(ColorType type)
		{
			return colorSet.get(type);
		}
		
		public void setColorByType(ColorType type, float[] colorF)
		{
			colorSet.put(type, colorF);
		}
		
		public void setColorByType(ColorType type, int[] color)
		{
			float[] colorF = new float[color.length];
			for (int i = 0; i < color.length; i++)
				colorF[i] = ((float)color[i] / 255.f);
			setColorByType(type, colorF);
		}
	}
	
	public enum ColorType
	{
		GIVE, NORMAL, TAKE, BOUNDARY, OUTER_BOUNDARY, ENERGY
	}
	
	private class ChangeColorThemeAction extends GameAction
	{
		ColorTheme oldColorTheme;
		ColorTheme newColorTheme;
		public ChangeColorThemeAction(long timeAllowed, ColorTheme oldColorTheme, ColorTheme newColorTheme) {
			super(timeAllowed);
			this.oldColorTheme = oldColorTheme;
			this.newColorTheme = newColorTheme;
		}
		
		public ColorTheme getColorTheme()
		{
			ColorTheme tempTheme;
			ColorSet basicSet = new ColorSet();
						
			//mix basic colorSet
			for (ColorType type : ColorType.values())
			{
				basicSet.setColorByType(type, ColorManager.mixColor(
						oldColorTheme.getBasicColorSet().getColorByType(type), 
						newColorTheme.getBasicColorSet().getColorByType(type),
						currentProgress()));
			}
			
			//mix alt colorSet
			if (newColorTheme.hasAltColorSet() || oldColorTheme.hasAltColorSet())
			{
				ColorSet altSet = new ColorSet();
				for (ColorType type : ColorType.values())
				{
					altSet.setColorByType(type, ColorManager.mixColor(
							oldColorTheme.hasAltColorSet()?
									oldColorTheme.getAltColorSet().getColorByType(type)
									:oldColorTheme.getBasicColorSet().getColorByType(type), 
							newColorTheme.hasAltColorSet()?
									newColorTheme.getAltColorSet().getColorByType(type)
									:newColorTheme.getBasicColorSet().getColorByType(type), 
							currentProgress()));
				}
				tempTheme = new ColorTheme(basicSet, altSet);
			}
			else
				tempTheme = new ColorTheme(basicSet);
			
			return tempTheme;
		}
		
	}
}

